<?php

namespace app\api\services\store;

use app\api\constant\OrderStatusConst;
use app\api\model\Coupon;
use app\api\model\CouponUser;
use app\api\model\GoodsProduct;
use app\api\model\Order;
use app\api\model\OrderGoods;
use app\api\model\UserAddress;
use app\api\services\BaseServices;
use app\api\services\user\AddressServices;
use app\api\util\Laravel;
use Carbon\Carbon;
use think\Collection;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\DbException;
use think\helper\Str;

class OrderServices extends BaseServices
{
    /**
     * 提交订单
     * @param int $userid
     * @param array $params
     * @return Order
     * @throws Exception
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function submit(int $userid, array $params): Order
    {
        $address = UserAddress::getByUserIdAddress($userid, $params['addressId']);
        if (empty($address)) {
            throw new Exception("地址不存在");
        }
        $cartGoodsList = CartServices::getInstance()->getCheckedCartLists($userid, $params['cartIds']);
        $checkGoodsPrice = CartServices::getInstance()->getCartPrice($cartGoodsList);
        $orderPrice = 0;
        // 优惠券金额
        $couponPrice = 0;
        if (!is_null($params['couponId'] ?? null) && $params['couponId'] > 0) {
            $coupon = Coupon::find($params['couponId']);
            $couponUser = CouponUser::find($params['userCouponId']);
            $is = CartServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $checkGoodsPrice);
            if ($is) {
                $couponPrice = $coupon['coupon_price'];
            }
        }
        $orderTotalPrice = bcsub($checkGoodsPrice, $couponPrice, 2);
        $orderTotalPrice = max(0, $orderTotalPrice);
        $order = new Order();
        $order->user_id = $userid;
        $order->address_id = $params['addressId'];
        $order->order_sn = self::generateOrderSn();
        $order->order_status = 101;
        $order->consignee = $address->real_name;
        $order->mobile = $address->phone;
        $order->address = $address->province . $address->city . $address->district . $address->detail;
        $order->message = $params['message'];
        $order->goods_price = $checkGoodsPrice;
        $order->freight_price = 0;
        $order->coupon_price = $couponPrice;
        $order->order_price = $orderTotalPrice;
        $order->actual_price = $orderTotalPrice;
        $order->createtime = time();
        $order->updatetime = time();

        $order->save();
        // 保存订单商品记录
        $cartGoodsList = (new Collection($cartGoodsList))->toArray();
        self::saveOrderGoods($cartGoodsList, $order->id);
        // 清理购物车
        CartServices::getInstance()->clearCartGoods($userid, $params['cartIds']);
        // 减库存
        self::reduceProductStock($cartGoodsList);
        return $order;

    }

    /**
     * @param $checkGoodsList
     * @param $orderId
     * @return void
     */
    private function saveOrderGoods($checkGoodsList, $orderId)
    {
        foreach ($checkGoodsList as $cart) {
            $orderGoods = new OrderGoods();
            $orderGoods->order_id = $orderId;
            $orderGoods->goods_id = $cart['store_goods_id'];
            $orderGoods->goods_sn = $cart['goods_sn'];
            $orderGoods->goods_name = $cart['goods_name'];
            $orderGoods->product_id = $cart['product_id'];
            $orderGoods->pic_url = $cart['pic_url'];
            $orderGoods->price = $cart['price'];
            $orderGoods->number = $cart['number'];
            $orderGoods->specifications = $cart['product']['specifications'];
            $orderGoods->save();
        }

    }

    /**
     * 判断订单号是否被使用过
     * @param $orderSn
     * @return bool
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function isOrderSnused($orderSn): bool
    {
        $order = Order::where('order_sn', $orderSn)->find();
        if ($order) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 生成订单号
     * @return mixed
     * @throws Exception
     */
    public function generateOrderSn()
    {
        return retry(5, function () {
            $orderSn = date('YmdHis') . Str::random(6);

            if (!$this->isOrderSnused($orderSn)) {
                return $orderSn;
            }
            throw new Exception("订单号生成失败");
        });
    }

    private function reduceProductStock($cartGoodsList)
    {

        $productIds = array_column($cartGoodsList, 'product_id');

        $products = GoodsProduct::whereIn('id', $productIds)->select();
        $products = (new Collection($products))->toArray();
        $products = Laravel::keyBy($products, 'id');
        foreach ($cartGoodsList as $cart) {
            $product = $products[$cart['product_id']];
            if (empty($product)) {
                throw new Exception("货品不存在");
            }
            if ($product['number'] < $cart['number']) {
                throw new Exception("库存不足");
            }
            $row = GoodsProduct::where('id', $product['id'])
                ->where('number', '>=', $cart['number'])
                ->setDec('number', $cart['number']);
            if (!$row) {
                throw new Exception("减少库存失败");
            }
        }
    }

    /**
     * 取消订单
     * @param $userId
     * @param $orderId
     * @param $role
     * @return void
     * @throws Exception
     */
    private function cancel($userId, $orderId, $role = 'user'): void
    {
        /** @var Order $order */
        $order = Order::getOrderByUserIdAndId($userId, $orderId);
        if (is_null($order)) {
            throw new Exception("订单不存在");
        }
        if ($order->canCancelHandle()) {
            throw new Exception("订单当前状态不支持被取消");
        }
        switch ($role) {
            case 'system': # 系统自动取消
                $order->order_status = OrderStatusConst::STATUS_CANCEL;
                break;
            case 'admin': # 管理员取消
                $order->order_status = OrderStatusConst::STATUS_ADMIN_CANCEL;
                break;
            default:
                $order->order_status = OrderStatusConst::STATUS_CANCEL;
        }
        $order->end_time = Carbon::now()->toDateTimeString();
        if ($order->cas($order->toArray()) === 0) {
            throw new Exception("取消失败");
        }
        $this->returnStock($orderId);
    }

    /**
     * 用户取消订单
     * @param $userid
     * @param $orderId
     * @return void
     */
    public function userCancel($userid, $orderId)
    {
        Db::transaction(function () use ($userid, $orderId) {
            $this->cancel($userid, $orderId, 'user');
        });
    }

    /**
     * 申请退款
     * @param $userid
     * @param $orderId
     * @return Order
     * @throws Exception
     */
    public function refund($userid, $orderId): Order
    {
        /** @var Order $order */
        $order = Order::getOrderByUserIdAndId($userid, $orderId);
        if (is_null($order)) {
            throw new Exception("订单不存在");
        }
        if (!$order->canReFundHandle()) {
            throw new Exception("该订单状态不支持退款");
        }
        $order->order_status = OrderStatusConst::STATUS_REFUND;
        $order->refund_apply_time = Carbon::now()->toDateTimeString();
        if ($order->cas($order->toArray()) == 0) {
            throw new Exception("操作失败");
        }
        return $order;
    }

    /**
     * 减少库存
     * @param $orderId
     * @return void
     * @throws Exception
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    private function returnStock($orderId)
    {
        $orderGoods = OrderGoods::where('order_id', $orderId)->select();
        foreach ($orderGoods as $good) {
            $row = GoodsServices::getInstance()->addStock($good['goods_id'], $good['number']);
            if ($row == 0) {
                throw new Exception("减库存失败");
            }
        }
    }

    /**
     * 确认收货
     * @param $userid
     * @param $orderId
     * @return Order
     * @throws Exception
     */
    public function confirm($userid, $orderId)
    {
        /** @var Order $order */
        $order = Order::getOrderByUserIdAndId($userid, $orderId, $isAuto = false);
        if (is_null($order)) {
            throw new Exception("订单不存在");
        }
        if (!$order->canConfirmHandle()) {
            throw new Exception("订单当前状态不支持确认收货");
        }
//        $order->comments = ;
        $order->order_status = $isAuto ? OrderStatusConst::STATUS_AUTO_CONFIRM : OrderStatusConst::STATUS_CONFIRM;
        $order->confirm_time = Carbon::now()->toDateTimeString();
        if ($order->cas($order->toArray()) == 0) {
            throw new Exception("操作失败");
        }
        return $order;
    }

    /**
     * 删除订单
     * @param $userId
     * @param $orderId
     * @return Order
     * @throws Exception
     */
    public function delete($userId, $orderId): Order
    {
        /** @var Order $order */
        $order = Order::getOrderByUserIdAndId($userId, $orderId);
        if (is_null($order)) {
            throw new Exception("订单不存在");

        }
        if (!$order->canDeleteHandle()) {
            throw new Exception("订单目前状态不能删除");
        }
        $order->delete();
        return $order;
    }

    /**
     * 订单详情
     * @param $userId
     * @param $orderId
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws Exception
     * @throws ModelNotFoundException
     */
    public function detail($userId, $orderId): array
    {
        $field = 'id,order_sn,message,createtime,consignee,mobile,ship_channel,ship_sn,address,order_status,goods_price,coupon_price,freight_price,actual_price,aftersale_status';
        /** @var Order $order */
        $order = Order::getOrderByUserIdAndId($userId, $orderId, $field);
        if (is_null($order)) {
            throw new Exception("订单不存在");
        }
        $detail = $order->toArray();
        $detail['order_status_text'] = OrderStatusConst::STATUS_TEXT_MAP[$order['order_status']] ?? "";
        $detail['handle_option'] = $order->getCanHandelOptions();
        $express = [];
        if ($order->order_status = OrderStatusConst::STATUS_SHIP) {
            $detail['exp_code'] = $order->ship_channel;
            $detail['exp_no'] = $order->ship_sn;
            $detail['exp_name'] = '待定';
            // TODO 物流信息
//            $express = [];
        }
        $goodsList = OrderGoods::where('order_id', $orderId)->select();
        return [
            'order_info' => $detail,
            'order_goods' => $goodsList,
            'express_info' => $express
        ];
    }
}
